\subsubsection{Parallelisierung der Dateiverarbeitung}$\;$ \\
Zu Beginn muss man erwähnen, dass die Parallelisierung der Dateiverarbeitung nur hilfreich ist bzw. die Performanz steigert, wenn ein Ordner, der mehr als eine Datei enthält, zu komprimieren ist. Außerdem kann es bei einer oder wenigen, kleinen Dateien dazu kommen, dass aufgrund des Zeitaufwands der Erstellung neuer Threads, die parallele Variante langsamer operiert als die sequentielle.\\
Grundsätzlich gibt es zwei theoretische Ansätze die Parallelisierung der Dateiverarbeitung durchzuführen. Der erste und simplere Ansatz ist es, ein Programm zu schreiben, welches mit Hilfe von System-Aufrufen das fertig kompilierte GZIP-Programm ausführt, wobei dieses auf Ebene des Komprimierungsalgorithmus sehr wohl parallelisiert ist. Dabei wird für jeden Aufruf des GZIP-Programms ein neuer Thread erstellt und somit erfolgt die Komprimierung mehrerer Dateien gleichzeitig. In der Theorie klingt dieser Ansatz logisch und wäre mit relativ geringem Zeitaufwand zu implementieren. In der Praxis wird Threading bei System-Aufrufen jedoch nicht unterstützt bzw. nicht angewendet (zumindest nicht unter OS X 10.8). Das heißt, obwohl neue Threads erstellt werden, führt das Betriebssystem die einzelnen GZIP-Programm-Aufrufe sequentiell und nicht parallel aus. \\ \\
Das Ziel des zweiten etwas aufwändigeren Ansatzes ist es, das GZIP Programm so umzuschreiben, dass mehrere Dateien gleichzeitig komprimiert werden. Um die Umsetzung dieses Ansatzes zu verstehen, ist es notwendig die grundlegende Funktionsweise des GZIP-Programms zu kennen. Die Pseudocode Abbildung der Datei gzip.c im folgenden Algorithmus Block \ref{alg:gzip_seq} soll diese grundlegende Funktionsweise von GZIP (sequenziell) zeigen. \\

\begin{lstlisting}[caption={GZip Programmübersicht (Pseudocode gzip.c, sequentiell)}, label=alg:gzip_seq]
/* Globale Variablen */
char *fileNameOrDir;
char *out;

int main (int argc, char **argv) {
  /* Behandlung der Eingabe Parameter (wie zB. fileNameOrDir oder 
     recursiveParam fuer das Zippen von Verzeichnissen) */
  fileNameOrDir = argv[0];
  treat_file(fileNameOrDir);  /* Start des eigentlichen Prozesses */
  return 0;
}

void treat_file(char *fileNameOrDir) {
  /* recursiveParam wird ueber die Eingabe Parameter gesetzt */
  if(fileNameOrDir == Dir && recursiveParam == TRUE) {
    treat_dir(fileNameOrDir);
  }
  setOutFileName();  /* setOutFileName() setzt den Out-Namen der gezippten Datei in der Variable out */
  zip(fileNameOrDir, out);  /* zip(...) uebernimmt die eigentliche Kompression */
}

void treat_dir(char *dir) {
  /* getNextEntryOfDir gibt immer die naechste Datei oder das naechste Verzeichnis zurueck */
  while((fileOrDir=getNextEntryOfDir(dir)) != NULL) {
    treat_file(fileOrDir);
  }
}
\end{lstlisting}
$\;$ \\ 
\noindent
Das Programm beginnt mit der Definition der globalen Variablen \textit{fileNameOrDir} und \textit{out} welche den Eingangs- und Ausgangsdateinamen entsprechen. Die \textit{main(...)} Methode kümmert sich zu Beginn um die Behandlung der Eingabe Parameter und ruft dann die Methode \textit{treat\_file(...)} auf, welche sich wie der Name bereits verrät um die Dateiverarbeitung kümmert. Wird nun als Eingabeparameter \textit{fileNameOrDir} ein Verzeichnis und als Zusatz \textit{-r} für die Rekursion angegeben, wird die Methode \textit{treat\_dir(...)} aufgerufen. Diese Methode übernimmt nun den rekursiven Aufruf von \textit{treat\_file(...)}, damit auch wirklich alle im Eingangsverzeichnis beinhalteten Dateien komprimiert werden. In \textit{treat\_file(...)} wird dann noch die Variable \textit{out} gesetzt und schlussendlich der eigentliche Komprimierungsalgorithmus aufgerufen (\textit{zip(...)}). Natürlich handelt es sich hierbei um eine sehr vereinfachte Darstellung der Funktionsweise von GZIP, allerdings wäre eine detaillierte Beschreibung zu unübersichtlich.\\
Um GZIP nun zu parallelisieren muss zuerst eine Stelle im Quellcode gefunden werden, die den sinnvollen Einsatz von Parallelisierung ermöglicht. Dafür bietet sich die Methode \textit{treat\_file(...)} an, da diese den eigentlichen Komprimierungsalgorithmus \textit{zip(...)} für jede Datei aufruft. Die Pseudocode Abbildung der Datei gzip.c im folgenden Algorithmus Block \ref{alg:gzip_par} soll die grundlegende Funktionsweise von GZIP (parallel) nach der Parallelisierung zeigen. \\

\begin{lstlisting}[caption={GZip Programmübersicht (Pseudocode gzip.c, parallel)}, label=alg:gzip_par]
int main (int argc, char **argv) {
  /* Behandlung der Eingabe Parameter (wie zB. fileNameOrDir oder 
     recursiveParam fuer das Zippen von Verzeichnissen) */
  char *fileNameOrDir = argv[0];
  treat_file(fileNameOrDir);  /* Start des eigentlichen Prozesses */
  return 0;
}

void treat_file(void *voidFileNameOrDir) {
  char *fileNameOrDir = (char *) voidFileNameOrDir; /* cast auf char* */
  
  /* recursiveParam wird ueber die Eingabe Parameter gesetzt */
  if(fileNameOrDir == Dir && recursiveParam == TRUE) {
    treat_dir(fileNameOrDir);
  }
  
  char *out = getOutFileName(fileNameOrDir); /* getOutFileName(...) gibt den Out-Namen der gezippten Datei zurueck */
  zip(fileNameOrDir, out);  /* zip(...) uebernimmt die eigentliche Kompression */
}

void treat_dir(char *dir) {
  /* Array an Threads um diese auch nach der Erstellung noch erreichen zu koennen */
  pthread_t threads[MAX_PATH_LEN];
  long t = 0;
  /* getNextEntryOfDir gibt immer die naechste Datei oder das naechste Verzeichnis zurueck */
  while((fileOrDir=getNextEntryOfDir(dir)) != NULL) {
    /* Hier passiert das eigentliche Erstellen der Threads */
    pthread_create(&threads[t], NULL, treat_file, (void *)fileOrDir);
    t++;
  }
}
\end{lstlisting}
$\;$ \\ 
\clearpage
\noindent Der generelle Ablauf des Algorithmus ist im Großen und Ganzen auch nach der Parallelisierung gleich geblieben. Um gzip.c zu parallelisieren war es jedoch zuerst einmal notwendig beinahe alle globalen in lokale Variablen zu ändern, da ansonsten mehrere Threads gleichzeitig auf die selben Variablen bzw. Speicherbereiche zugegriffen hätten, was natürlich zu Fehlern bzw. Programmabstürzen führen würde. Die Änderung von globalen hinzu lokalen Variablen soll am Beispiel der \textit{out} Variable gezeigt werden. So wurde zuvor die globale Variable \textit{out} noch in der Methode \textit{setOutFileName(...)} gesetzt. Nun wird \textit{out} innerhalb der \textit{treat\_file(...)} Methode gesetzt. Somit verwendet die Methode \textit{zip(...)} nur noch lokale und damit thread-sichere Variablen (siehe \textit{getOutFileName(fileNameOrDir)}).\\
Außerdem musste die Methode \textit{treat\_file(...)} etwas abgeändert werden, da Methoden, bei der Kreation von Threads nur mit maximal einem \textit{void*} Parameter aufgerufen werden können. Das eigentliche Erstellen der Threads findet dann in der Methode \textit{treat\_dir(...)} statt indem die POSIX-Methode \textit{pthread\_create(\&threads[t], NULL, treat\_file, (void *)fileOrDir)} aufgerufen wird. Diese kümmert sich um das Erstellen der Threads und das Aufrufen der angegebenen Methode (\textit{treat\_file}) mit dem angegebenen Parameter \textit{(void *)fileOrDir}. Danach kommt es in jedem neu erstellten Thread zum Aufruf der \textit{zip(...)} Methode, sofern es sich um eine Datei handelt.

\clearpage